package net
{
	import event.AMFEvent;
	
	import flash.events.AsyncErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.NetStatusEvent;
	import flash.net.NetConnection;
	import flash.net.Responder;
	import flash.utils.describeType;
	
	public class RSAConnection extends EventDispatcher
	{
		private var remoteURL:String;
		private var connection:NetConnection;
		private var serviceName:String;
		private var argsData:Array;
		private var connected:Boolean = false;
		
		private const AMFPHP_FILE_NOT_FOUND:String = "AMFPHP_FILE_NOT_FOUND";
		private const AMFPHP_INEXISTANT_METHOD:String = "AMFPHP_INEXISTANT_METHOD";
		
		public function RSAConnection(remoteURL:String,serviceName:String,validateFunc:String)
		{
			super();
			this.remoteURL = remoteURL;
			this.serviceName = serviceName;
			argsData = new Array;
			connection = new NetConnection;
			connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
			connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
		
			connection.connect(remoteURL);
			var responder:Responder = new Responder(onValidateConnection,connectionFailed);
			connection.call(serviceName+'.'+validateFunc,responder);
		}
		private function dispatchException(value:Object):void{
			
			var amfException:AMFException = AMFException.fromObject(value);
			var str:String = amfException.description;
			var re:RegExp = /.*{(.*?)}.*.{(.*?)}.*/;
			var out:String = null;
			if(amfException.code == AMFPHP_INEXISTANT_METHOD){
				out = str.replace(re,"no method '$1' in class '$2'");
				dispatchEvent(new AMFEvent(AMFEvent.INEXISTANT_METHOD,out));
			}
			else if(amfException.code == AMFPHP_FILE_NOT_FOUND){
				out = str.replace(re,"class '$1' not found");
				dispatchEvent(new AMFEvent(AMFEvent.FILE_NOT_FOUND,out));
			}
		}
		private function connectionFailed(e:Object):void{
			connected = false;
			dispatchException(e);
			dispatchEvent(new AMFEvent(AMFEvent.CONNECTED,false));
		}
		private function responseError(e:*):void{
			dispatchException(e);
		}
		private function onValidateConnection(connected:Boolean):void{
			connected = true;
			dispatchEvent(new AMFEvent(AMFEvent.CONNECTED,true));
			if(argsData.length){
				var data:Array;
				for each(data in argsData){
					callNow(data);
				}
				argsData.length = 0;
			}
		}
		public function call(functionName:String,...args):void{
			var responder:Responder = new Responder(onResult,responseError);
			var arr:Array = [serviceName + '.' + functionName, responder];
			var i:uint;
			for (i=0;i< args.length;i++) {
				arr.push(args[i]);
			}
			if(connected){
				callNow(arr);
			}
			else{
				argsData.push(arr);
			}
		}
		private function callNow(args:Array):void{
			connection.call.apply(this, args);
		}
		private function onResult(data:Object=null):void{
			dispatchEvent(new AMFEvent(AMFEvent.RESULT,data));
		}
		private function onNetStatus(e:NetStatusEvent):void{
			trace(e.type,e.info.code);
			//code : NetConnection.Call.Failed
			//details : amfphp/gateway2.php
			//description : HTTP: Failed
			traceObject(e.info);
			dispatchEvent(new AMFEvent(AMFEvent.NET_STATUS_ERROR));
		}
		private function onAsyncError(e:AsyncErrorEvent):void{
			trace(e.type);
			traceObject(e.error);
		}
		private function traceObject(value:Object):void{
			if(value is String) trace(value);
			else{
				for(var p:* in value) trace(p,":",value[p]);
			}
		}
	}
}